package com.lp.ezuiz;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import org.apache.commons.httpclient.util.DateUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.lp.bean.IotVideoInfo;
import com.lp.bean.VideoFileInfo;
import com.lp.bo.IotVideoInfoBO;
import com.lp.cfg.ProConfig;
import com.lp.common.Code;
import com.lp.common.Constants;
import com.lp.service.impl.BaseServiceImpl;
import com.lp.util.CommonUtil;
import com.lp.util.HttpServiceSender;
import com.lp.util.JsonUtils;
import com.lp.util.ObjectUtil;

import net.sf.json.JSONObject;


@Component
@EnableScheduling
@Service
public class EzuizService extends BaseServiceImpl{
	
	public static String EZUIZ_TOKEN = StringUtils.EMPTY;
	
	public static final String DOMAIN = "https://open.ys7.com";
	//获取token
	public static final String GET_TOKEN = DOMAIN +"/api/lapp/token/get";
	//添加设备
	public static final String ADD_DEVICE = DOMAIN + "/api/lapp/device/add";
	//删除设备
	public static final String DELETE_DEVICE = DOMAIN + "/api/lapp/device/delete";
	//修改设备名称
	public static final String UPDATE_DEVICE_NAME = DOMAIN + "/api/lapp/device/name/update";
	//获取视频设备列表
	public static final String SELECT_CAMERA_LIST = DOMAIN + "/api/lapp/camera/list";
	//获取设备信息
	public static final String SELECT_ONE_DEVICE = DOMAIN + "/api/lapp/device/info";
	
	//云台控制相关
	//开始云台控制
	public static final String DEVICE_PTZ_START = DOMAIN + "/api/lapp/device/ptz/start";
	//停止云台控制
	public static final String DEVICE_PTZ_STOP = DOMAIN + "/api/lapp/device/ptz/stop";
	//镜像翻转（需设备支持）
	public static final String DEVICE_PTZ_MIRROR = DOMAIN + "/api/lapp/device/ptz/mirror";
	
	//设备抓拍图片
	public static final String DEVICE_CAPTURE = DOMAIN + "/api/lapp/device/capture";
	
	//关闭设备视频加密
	public static final String ENCRYPT_OFF = DOMAIN + "/api/lapp/device/encrypt/off";
	//开启设备视频加密
	public static final String ENCRYPT_ON = DOMAIN + "/api/lapp/device/encrypt/on";

	private static Logger logger = Logger.getLogger(EzuizService.class);
	
	//每天凌晨一点执行一次
	@Scheduled(cron = "0 0 1 * * ?")
	public void run() {
		refreshToken();
	}
	
	//添加设备
	public Map<String, Object> addDevice(IotVideoInfo video) {
		Map<String, Object> resultMap = getResultMap();
		putStatusCode(resultMap, Code.ResponseCode.SystemCode.ERROR);
		try {
			String[] result = HttpServiceSender.doPost(ADD_DEVICE+"?accessToken="+EZUIZ_TOKEN+"&deviceSerial="+video.getDevice_serial()+"&validateCode="+video.getValidate_code(), "", "");
			if(isOkEzuiz(result[1])) {
				//修改名称
				// updateDeviceName(video);
				putStatusCode(resultMap, Code.ResponseCode.SystemCode.OK);
			}else{
				com.alibaba.fastjson.JSONObject json = JSON.parseObject(result[1]);
				putStatusMsg(resultMap , json.getString("msg")) ;
			}
		} catch (Exception e) {
			logger.error( e.getMessage()  +", param = " + JSON.toJSONString(video));
		}
		return resultMap;
	}
	
	//删除设备
	public Map<String, Object> deleteDevice(IotVideoInfo video) {
		Map<String, Object> resultMap = getResultMap();
		putStatusCode(resultMap, Code.ResponseCode.SystemCode.ERROR);
		try {
			String[] result = HttpServiceSender.doPost(DELETE_DEVICE+"?accessToken="+EZUIZ_TOKEN+"&deviceSerial="+video.getDevice_serial(), "", "");
			com.alibaba.fastjson.JSONObject json = JSON.parseObject(result[1]);
			logger.error(json.getString("msg"));
			// 只要不保错就可以
			putStatusCode(resultMap, Code.ResponseCode.SystemCode.OK);
		} catch (Exception e) {
			logger.error("deleteDevice error, "+ e.getMessage()  +", param = " + JSON.toJSONString(video));
		}
		return resultMap;
	}
	//修改设备名称
	public Map<String, Object> updateDeviceName(IotVideoInfo video) {
		Map<String, Object> resultMap = getResultMap();
		putStatusCode(resultMap, Code.ResponseCode.SystemCode.ERROR);
		try {
			//检索当前设备信息
			IotVideoInfoBO vp = new IotVideoInfoBO();
			vp.setId(video.getId());
			IotVideoInfoBO v = dao.selectOne("IotVideoInfo.selectOne", vp);
			if(v != null && ObjectUtil.isNotEmpty(v.getDevice_serial())) {
				String[] result = HttpServiceSender.doPost(UPDATE_DEVICE_NAME+"?accessToken="+EZUIZ_TOKEN+"&deviceSerial="+v.getDevice_serial()+"&deviceName="+video.getName(), "", "");
				if(isOkEzuiz(result[1])) {
					putStatusCode(resultMap, Code.ResponseCode.SystemCode.OK);
				}
			}
		} catch (Exception e) {
			logger.error("updateDeviceName error, "+ e.getMessage()  +", param = " + JSON.toJSONString(video));
		}
		return resultMap;
	}
	
	//设备抓拍图片
	public Map<String, Object> deviceCapture(IotVideoInfo video) {
		Map<String, Object> resultMap = getResultMap();
		putStatusCode(resultMap, Code.ResponseCode.SystemCode.ERROR);
		try {
			//检索当前设备信息
			IotVideoInfoBO vp = new IotVideoInfoBO();
			vp.setId(video.getId());
			IotVideoInfoBO v = dao.selectOne("IotVideoInfo.selectOne", vp);
			if(v != null && ObjectUtil.isNotEmpty(v.getDevice_serial())) {
				String[] result = HttpServiceSender.doPost(DEVICE_CAPTURE+"?accessToken="+EZUIZ_TOKEN+"&deviceSerial="+v.getDevice_serial()+"&channelNo="+v.getChannel(), "", "");
				if(isOkEzuiz(result[1])) {
					//图片存储
					VideoFileInfo vf = new VideoFileInfo();
					vf.setVideo_id(v.getId());
					vf.setName(v.getName()+"_"+System.currentTimeMillis());
					vf.setFix("jpg");
					String filepath = "/videofile/"+ DateUtil.formatDate(new Date(), "yyyMMdd")  ;
					String fileName = "/" + System.currentTimeMillis() +"."+vf.getFix()  ;
					vf.setUrl( filepath + fileName );
					vf.setDelete_flag(Constants.DELETE.NO);
					dao.insert("VideoFileInfo.insert", vf);
					Map data = getDataMap(result[1]);
					//保存图片到本地
					saveFile(data.get("picUrl").toString(),filepath , fileName );
					putStatusCode(resultMap, Code.ResponseCode.SystemCode.OK);
				}
			}
		} catch (Exception e) {
			logger.error("device capture error, "+ e.getMessage()  +", param = " + JSON.toJSONString(video));
		}
		return resultMap;
	}
	
	//设备同步
	public Map<String, Object> synchronizDevice(IotVideoInfo video) {
		Map<String, Object> resultMap = getResultMap();
		putStatusCode(resultMap, Code.ResponseCode.SystemCode.ERROR);
		try {
			IotVideoInfoBO vp = new IotVideoInfoBO();
			vp.setScene_id(video.getScene_id());
			//检索已有设备
			Vector<String> vs = new Vector<String>();
			List<IotVideoInfoBO> videos = dao.selectList("IotVideoInfo.select", vp);
			if(videos != null && videos.size()>0) {
				for(IotVideoInfoBO v: videos) {
					if(!vs.contains(v.getDevice_serial())) {
						vs.add(v.getDevice_serial());
					}
				}
			}
			List<Map> devices = getDeviceList();
			if(devices != null && devices.size()>0) {
				for(Map d:devices) {
					String device_serial = d.get("deviceSerial").toString();
					if(device_serial != null && !device_serial.isEmpty() && !vs.contains(device_serial)) {
						//数据库中没有当前视频设备，添加到数据库中
						vp.setDevice_serial(d.get("deviceSerial").toString());
						vp.setChannel(d.get("channelNo").toString());
						vp.setName(d.get("channelName").toString());
						vp.setVideo_type(Code.VIDEO_INPUT_TYPE.HIK_INPUT);
						int status = CommonUtil.parseInt(d.get("status"));
						vp.setStatus(Code.DEVICE_STATUS.OFFLINE);
						if(status == 1) {
							vp.setStatus(Code.DEVICE_STATUS.ONLINE);
						}
						vp.setAtime(new Date());
						vp.setDelete_flag(0);
						vp.setSeq(1);
						dao.insert("IotVideoInfo.insert", vp);
					}
				}
			}
			putStatusCode(resultMap, Code.ResponseCode.SystemCode.OK);
		} catch (Exception e) {
			logger.error("sync device error, param = " + JSON.toJSONString(video));
		}
		return resultMap;
	}
	
	public static List<Map> getDeviceList(int... paged) {
		List<Map> devices = new ArrayList<Map>();
		int paged_ = 0;
		int page_size = 50;
		String param = StringUtils.EMPTY;
		if(paged!=null && paged.length!=0) {
			param = "pageStart="+paged[0]+"&pageSize="+page_size;
			paged_ = paged[0];
		}
		String[] result = HttpServiceSender.doPost(SELECT_CAMERA_LIST+"?accessToken="+EZUIZ_TOKEN+param, "", "");
		if(isOkEzuiz(result[1])) {
			devices.addAll(getDataList(result[1]));
			//分页同步后面所有的设备
			Map pagebean = (Map) JsonUtils.json2Object(result[1], "page", Map.class);
			if(pagebean != null) {
				int total = CommonUtil.parseInt(pagebean.get("total"));
				paged_++;
				if(total>0 && (total/page_size+1)>paged_) {
					devices.addAll(getDeviceList(paged_));
				}
			}
		}
		return devices;
	}
	
	
	//开始云台控制
	public Map<String, Object> ptzStart(IotVideoInfoBO video) {
		Map<String, Object> resultMap = getResultMap();
		putStatusCode(resultMap, Code.ResponseCode.SystemCode.ERROR);
		try {
			//检索当前设备信息
			IotVideoInfoBO vp = new IotVideoInfoBO();
			vp.setId(video.getId());
			IotVideoInfoBO v = dao.selectOne("IotVideoInfo.selectOne", vp);
			String param = "&deviceSerial="+v.getDevice_serial()+"&channelNo="+v.getChannel()+"&direction="+video.getDirection()+"&speed="+video.getSpeed();
			String[] result = HttpServiceSender.doPost(DEVICE_PTZ_START+"?accessToken="+EZUIZ_TOKEN+param, "", "");
			if(isOkEzuiz(result[1])) {
				putStatusCode(resultMap, Code.ResponseCode.SystemCode.OK);
			}
		} catch (Exception e) {
			logger.error("add device error, param = " + JSON.toJSONString(video));
		}
		return resultMap;
	}
	
	//停止云台控制
	public Map<String, Object> ptzStop(IotVideoInfoBO video) {
		Map<String, Object> resultMap = getResultMap();
		putStatusCode(resultMap, Code.ResponseCode.SystemCode.ERROR);
		try {
			//检索当前设备信息
			IotVideoInfoBO vp = new IotVideoInfoBO();
			vp.setId(video.getId());
			IotVideoInfoBO v = dao.selectOne("IotVideoInfo.selectOne", vp);
			String param = "&deviceSerial="+v.getDevice_serial()+"&channelNo="+v.getChannel();
			if(ObjectUtil.isNotEmpty(video.getDirection())) {
				//建议传递方向
				param = param + "&direction="+video.getDirection();
			}
			String[] result = HttpServiceSender.doPost(DEVICE_PTZ_STOP+"?accessToken="+EZUIZ_TOKEN + param, "", "");
			if(isOkEzuiz(result[1])) {
				putStatusCode(resultMap, Code.ResponseCode.SystemCode.OK);
			}
		} catch (Exception e) {
			logger.error("ptz stop error, param = " + JSON.toJSONString(video));
		}
		return resultMap;
	}
	//关闭设备视频加密
	public Map<String, Object> encryptOff(IotVideoInfo video) {
		Map<String, Object> resultMap = getResultMap();
		putStatusCode(resultMap, Code.ResponseCode.SystemCode.ERROR);
		try {
			//检索当前设备信息
			IotVideoInfoBO vp = new IotVideoInfoBO();
			vp.setId(video.getId());
			IotVideoInfoBO v = dao.selectOne("IotVideoInfo.selectOne", vp);
			if(v != null && ObjectUtil.isNotEmpty(v.getDevice_serial())) {
				String param = "&deviceSerial="+v.getDevice_serial()+"&validateCode="+v.getValidate_code();
				String[] result = HttpServiceSender.doPost(ENCRYPT_OFF+"?accessToken="+EZUIZ_TOKEN + param, "", "");
				if(isOkEzuiz(result[1])) {
					putStatusCode(resultMap, Code.ResponseCode.SystemCode.OK);
				}
			}
		} catch (Exception e) {
			logger.error( e.getMessage() + " , param = " + JSON.toJSONString(video));
		}
		return resultMap;
	}
	//开启设备视频加密
	public Map<String, Object> encryptOn(IotVideoInfo video) {
		Map<String, Object> resultMap = getResultMap();
		putStatusCode(resultMap, Code.ResponseCode.SystemCode.ERROR);
		try {
			//检索当前设备信息
			IotVideoInfoBO vp = new IotVideoInfoBO();
			vp.setId(video.getId());
			IotVideoInfoBO v = dao.selectOne("IotVideoInfo.selectOne", vp);
			if(v != null && ObjectUtil.isNotEmpty(v.getDevice_serial())) {
				String[] result = HttpServiceSender.doPost(ENCRYPT_ON+"?accessToken="+EZUIZ_TOKEN + "&deviceSerial="+v.getDevice_serial(), "", "");
				if(isOkEzuiz(result[1])) {
					putStatusCode(resultMap, Code.ResponseCode.SystemCode.OK);
				}
			}
		} catch (Exception e) {
			logger.error( e.getMessage() + " , param = " + JSON.toJSONString(video));
		}
		return resultMap;
	}
	
	//刷新token
	public static void refreshToken() {
		try {
			String[] result = HttpServiceSender.doPost(GET_TOKEN+"?appKey="+ProConfig.EZUIZ_APPKEY+"&appSecret="+ProConfig.EZUIZ_APPSECRET, "", "");
			if(isOkEzuiz(result[1])) {
				Map data = getDataMap(result[1]);
				EZUIZ_TOKEN = data.get("accessToken").toString();
			}
		} catch (Exception e) {
			logger.error( e.getMessage() );
		}
	}
	
	
	
	public static Boolean isOkEzuiz(String result) {
		Map data = (Map) JsonUtils.json2Object(result, Map.class);
		if(data != null) {
			String status_code = data.get("code").toString();
			if(status_code != null) {
				if(status_code.equals("200")) {
					return true;
				}else if(status_code.equals("10002")) {
					//token过期刷新token
					refreshToken();
				}
				
			}
		}else if(EZUIZ_TOKEN.isEmpty()) {
			refreshToken();
		}
		return false;
	}
	
	public static Map getDataMap(String result) {
		try {
			Map data = (Map) JsonUtils.json2Object(result, "data", Map.class);
			return data;
		} catch (Exception e) {
			logger.error( e.getMessage() );
		}
		return null;
	}
	
	public static List<Map> getDataList(String result) {
		try {
			JSONObject jo = JSONObject.fromObject(result);
			List<Map> data = (List<Map>) JsonUtils.json2List(jo.get("data").toString(), Map.class);
			return data;
		} catch (Exception e) {
			logger.error( e.getMessage() );
		}
		return null;
	}

	public static void mkdirs(String destPath) {
		File file = new File(destPath);
		if (!file.exists() && !file.isDirectory()) {
			file.mkdirs();
		}
	}
	
	/**
	 * 图片保存到本地
	 * @param img_url
	 */
	public static void saveFile(String img_url,String filePath, String name) {
		try {
			String file_path = ProConfig.LOCAL_FILE_PATH;
			//new一个URL对象  
	        URL url = new URL(img_url);  
	        //打开链接  
	        HttpURLConnection conn = (HttpURLConnection)url.openConnection();  
	        //设置请求方式为"GET"  
	        conn.setRequestMethod("GET");  
	        //超时响应时间为5秒  
	        conn.setConnectTimeout(5 * 1000);  
	        //通过输入流获取图片数据  
	        InputStream inStream = conn.getInputStream();  
	        //得到图片的二进制数据，以二进制封装得到数据，具有通用性  
	        byte[] data = readInputStream(inStream);  
	        //new一个文件对象用来保存图片，默认保存当前工程根目录
	        new File(file_path + filePath ).mkdirs();
	        File imageFile = new File(file_path+ filePath + name );
	        //创建输出流  
	        FileOutputStream outStream = new FileOutputStream(imageFile);  
	        //写入数据  
	        outStream.write(data);  
	        //关闭输出流  
	        outStream.close();
		} catch (Exception e) {
			logger.error( e.getMessage() );
		}
	}
    public static byte[] readInputStream(InputStream inStream) throws Exception{  
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();  
        //创建一个Buffer字符串  
        byte[] buffer = new byte[1024];  
        //每次读取的字符串长度，如果为-1，代表全部读取完毕  
        int len = 0;  
        //使用一个输入流从buffer里把数据读取出来  
        while( (len=inStream.read(buffer)) != -1 ){  
            //用输出流往buffer里写入数据，中间参数代表从哪个位置开始读，len代表读取的长度  
            outStream.write(buffer, 0, len);  
        }  
        //关闭输入流  
        inStream.close();  
        //把outStream里的数据写入内存  
        return outStream.toByteArray();  
    } 
    
}
